﻿using CommonServiceLocator;
using NLog.Targets;
using OneOfAll.Common.Bussiness;
using OneOfAll.Common.Models;
using OneOfAll.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OneOfAll.UserControls
{
    /// <summary>
    /// PeopleControl.xaml 的交互逻辑
    /// </summary>
    public partial class PeopleControl : UserControl
    {

        public PeopleModel Info
        {
            get { return (PeopleModel)GetValue(InfoProperty); }
            set { SetValue(InfoProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Info.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InfoProperty =
            DependencyProperty.Register("Info", typeof(PeopleModel), typeof(PeopleControl), new PropertyMetadata(null));

        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        // Using a DependencyProperty as the backing store for X.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty XProperty =
            DependencyProperty.Register("X", typeof(double), typeof(PeopleControl), new PropertyMetadata(0.0, (sender, e) =>
            {
                var dp = sender as PeopleControl;
                if (dp == null) return;
                dp.XChanged();
            }));



        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Y.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YProperty =
            DependencyProperty.Register("Y", typeof(double), typeof(PeopleControl), new PropertyMetadata(0.0, (sender, e) =>
            {
                var dp = sender as PeopleControl;
                if (dp == null) return;
                dp.YChanged();
            }));

        Storyboard storyboard;

        private double breakX = -1.0;
        private double breakY = -1.0;

        private void XChanged()
        {
            if (breakX >= 0)
            {
                breakX = -1.0;
                return;
            }
            if (Info != null)
                Info.X = X;
        }

        private void YChanged()
        {
            if (breakY >= 0)
            {
                breakY = -1.0;
                return;
            }
            if (Info != null)
                Info.Y = Y;
        }

        public void Start()
        {
            ExcuteBehavior();
        }

        private void ExcuteBehavior()
        {
            //Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.ffff")} 开始执行行为{Info.Status}");
            RefushStatus();
            List<DoubleAnimationBase> animations;
            switch (Info.Status)
            {
                case ObjectStatusEnum.空闲:
                    animations = GetStandAnimation();
                    break;
                case ObjectStatusEnum.死亡:
                    animations = GetDeadBehavior();
                    break;
                case ObjectStatusEnum.移动:
                    animations = GetMoveBehavior();
                    break;
                default:
                    animations = GetStandAnimation();
                    break;
            }
            if (storyboard != null)
            {
                storyboard.Stop();
                foreach (var animation in storyboard.Children)
                {
                    animation.Completed -= Animation_Completed;
                }
                storyboard.Children.Clear();
            }
            storyboard = new Storyboard();
            foreach (var animation in animations)
            {
                animation.Completed += Animation_Completed;
                storyboard.Children.Add(animation);
            }
            storyboard.Begin(this, true);
        }

        private List<DoubleAnimationBase> GetMoveBehavior()
        {
            List<Point> path = GetMovePath();
            if (path == null)
            {
                Info.Status = ObjectStatusEnum.空闲;
                return GetStandAnimation();
            }
            return GetMoveAnimation(path);
        }

        private List<DoubleAnimationBase> GetMoveAnimation(List<Point> path)
        {
            if (path == null || path.Count == 0)
                return GetStandAnimation();

            List<DoubleAnimationBase> animations = new List<DoubleAnimationBase>();
            //创建故事板

            int cost = Global.GlobalResource.GameSpeed / (Info.Speed / Global.GlobalResource.GridSize);
            DoubleAnimationUsingKeyFrames keyFramesAnimationX = new DoubleAnimationUsingKeyFrames();
            keyFramesAnimationX.FillBehavior = FillBehavior.HoldEnd;
            keyFramesAnimationX.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * cost));
            Storyboard.SetTarget(keyFramesAnimationX, this);
            Storyboard.SetTargetProperty(keyFramesAnimationX, new PropertyPath("X"));
            DoubleAnimationUsingKeyFrames keyFramesAnimationY = new DoubleAnimationUsingKeyFrames();
            keyFramesAnimationY.FillBehavior = FillBehavior.HoldEnd;
            keyFramesAnimationY.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * cost));
            Storyboard.SetTarget(keyFramesAnimationY, this);
            Storyboard.SetTargetProperty(keyFramesAnimationY, new PropertyPath("Y"));
            for (int i = 0; i <= path.Count(); i++)
            {
                //加入X轴方向的匀速关键帧
                LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame();
                keyFrame.Value = i == 0 ? Info.X : path[i - 1].X;
                keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
                keyFramesAnimationX.KeyFrames.Add(keyFrame);
                keyFrame = new LinearDoubleKeyFrame();
                keyFrame.Value = i == 0 ? Info.Y : path[i - 1].Y;
                keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
                keyFramesAnimationY.KeyFrames.Add(keyFrame);
            }
            animations.Add(keyFramesAnimationX);
            animations.Add(keyFramesAnimationY);

            return animations;
        }

        private List<Point> GetMovePath()
        {
            if (Info.TargetKey != -1)
            {
                return ServiceLocator.Current.GetInstance<CityViewModel>().GetWorkPath(Info, Info.TargetKey);
            }
            else if (Info.Vitality > 0)
            {
                Random rd = new Random(Guid.NewGuid().GetHashCode());
                if (Info.X == Info.HomeX * Global.GlobalResource.GridSize && Info.Y == Info.HomeY * Global.GlobalResource.GridSize)
                {
                    var fullList = Global.GlobalResource.ArchiveInfo.CityInfo.GetFullConstruction();
                    var enabledList = Info.CityWalkPathList.Where(t => !fullList.Contains(t.Key)).ToList();
                    if (enabledList.Count <= 0)
                    {
                        return null;
                    }
                    var data = enabledList[rd.Next(enabledList.Count)];
                    var construction = Global.GlobalResource.ArchiveInfo.CityInfo.ConstructionList.FirstOrDefault(t => t.Key == data.Key);
                    if (construction == null) return null;
                    Info.TargetKey = construction.Key;
                    if (!construction.Plan_PeopleList.Contains(Info.Key))
                        construction.Plan_PeopleList.Add(Info.Key);
                    return data.Path;
                }
                else
                    return ServiceLocator.Current.GetInstance<CityViewModel>().GetWorkPath(Info);
            }
            else
            {
                Info.TargetKey = Info.HomeKey;
                return ServiceLocator.Current.GetInstance<CityViewModel>().GetBackPath(Info);
            }
        }

        private List<DoubleAnimationBase> GetDeadBehavior()
        {
            DoubleAnimation deadAnimation = new DoubleAnimation()
            {
                From = 1,
                To = 0,
                Duration = new Duration(new TimeSpan(0, 0, Global.GlobalResource.GameSpeed * 2))
            };
            Storyboard.SetTarget(deadAnimation, this);
            Storyboard.SetTargetProperty(deadAnimation, new PropertyPath("Opacity"));
            return new List<DoubleAnimationBase>() { deadAnimation };
        }

        private List<DoubleAnimationBase> GetStandAnimation()
        {
            DoubleAnimation idleAnimation = new DoubleAnimation()
            {
                From = Info.Y,
                To = Info.Y + Global.GlobalResource.GridSize / 2,
                AutoReverse = true,
                Duration = new Duration(new TimeSpan(0, 0, 0, 0, Global.GlobalResource.GameSpeed / 2))
            };
            Storyboard.SetTarget(idleAnimation, this);
            Storyboard.SetTargetProperty(idleAnimation, new PropertyPath("Y"));
            return new List<DoubleAnimationBase>() { idleAnimation };
        }

        private void RefushStatus()
        {
            if (Info.IsGoOut)
            {
                ScreenHelper.Instance.GetPeopleStatus(Info.ScreenName, Info);
            }
        }

        private void Animation_Completed(object sender, EventArgs e)
        {
            foreach (var animation in storyboard.Children)
            {
                animation.Completed -= Animation_Completed;
            }
            storyboard.Children.Clear();
            switch (Info.Status)
            {
                case ObjectStatusEnum.死亡:
                    Info.IsDispose = true;
                    break;
                case ObjectStatusEnum.空闲:
                    Info.TargetKey = -1;
                    if (!Info.IsGoOut)
                    {
                        Info.Status = ObjectStatusEnum.移动;
                        ExcuteBehavior();
                    }
                    else
                        ExcuteBehavior();
                    break;
                case ObjectStatusEnum.移动:
                    if (!Info.IsGoOut)
                    {
                        var construction = Global.GlobalResource.ArchiveInfo.CityInfo.ConstructionList.FirstOrDefault(t => t.Key == Info.TargetKey);
                        Info.TargetKey = -1;
                        if (construction == null) Info.Status = ObjectStatusEnum.空闲;
                        else
                        {
                            bool flag = false;
                            switch (construction.ConstructionType)
                            {
                                case ConstructionTypeEnum.培养:
                                    flag = DataCenterManager.Instance.MaterialsResourceCheck(Global.GlobalResource.ArchiveInfo.MaterialsResource, construction.TrainInfo.Cost, 1);
                                    if (flag)
                                        DataCenterManager.Instance.MaterialsResourceRemove(Global.GlobalResource.ArchiveInfo.MaterialsResource, construction.TrainInfo.Cost, 1);
                                    break;
                                case ConstructionTypeEnum.生产:
                                case ConstructionTypeEnum.居住:
                                    flag = true;
                                    break;
                                case ConstructionTypeEnum.制作:
                                    flag = DataCenterManager.Instance.MaterialsResourceCheck(Global.GlobalResource.ArchiveInfo.MaterialsResource, construction.MakeInfo.Cost, 1);
                                    if (flag)
                                        DataCenterManager.Instance.MaterialsResourceRemove(Global.GlobalResource.ArchiveInfo.MaterialsResource, construction.MakeInfo.Cost, 1);
                                    break;
                            }
                            if (flag)
                            {
                                construction.PeopleList.Add(new PeopleWorkInfoModel()
                                {
                                    Key = Info.Key,
                                    Name = Info.Name,
                                    Schedule = GetSchedule(construction),
                                    WorkSpeed = GetWorkSpeed(construction) * Info.Mood / 100.0,
                                    MaxValue = GetMaxValue(construction)
                                });
                                Info.Status = ObjectStatusEnum.工作;
                                Info.WorkKey = construction.Key;
                                Info.IsDispose = true;
                            }
                            else
                            {
                                Info.TargetKey = -1;
                                if (!Info.IsGoOut)
                                {
                                    Info.Status = ObjectStatusEnum.移动;
                                    ExcuteBehavior();
                                }
                            }
                        }
                    }
                    else
                        ExcuteBehavior();
                    break;
                default:
                    break;
            }
        }

        private double GetSchedule(ConstructionModel construction)
        {
            switch (construction.ConstructionType)
            {
                case ConstructionTypeEnum.居住:
                    return Info.Vitality;
                default:
                    return 0;
            }
        }

        private double GetMaxValue(ConstructionModel construction)
        {
            switch (construction.ConstructionType)
            {
                case ConstructionTypeEnum.居住:
                    return Info.MaxVitality;
                case ConstructionTypeEnum.生产:
                    return construction.ProductionInfo.Workload;
                case ConstructionTypeEnum.制作:
                    return construction.MakeInfo.WorkLoad;
                default:
                    return 100;
            }
        }

        private double GetWorkSpeed(ConstructionModel construction)
        {
            switch (construction.ConstructionType)
            {
                case ConstructionTypeEnum.生产:
                    return Info.Potential_Power;
                case ConstructionTypeEnum.培养:
                    return Info.Potential_Wit;
                case ConstructionTypeEnum.制作:
                    return Info.Potential_Trick;
                case ConstructionTypeEnum.居住:
                    return construction.LiveInfo.RestRatio * Info.Potential_Strong;
                default:
                    return 10.0;
            }
        }

        public void Stop()
        {
            if (storyboard != null) storyboard.Stop(this);
            breakX = Info.X;
            breakY = Info.Y;
        }

        public PeopleControl()
        {
            InitializeComponent();
        }
    }
}
